#include "Command.h"

void Command::Command()
{
	cmd_functions = NULL;
}

void Command::init()
{
	//  register our commands
	add_command( "cmdlist" );
	add_command( "exec" );
	add_command( "echo" );
	add_command( "alias" );
	add_command( "wait" );
}

void Command::add_command( char* cmd_name, xcommand_t function )
{
	Command::Func* cmd_functions;
	Command::Func* cmd;
	CommandVariable cvar*;

	// fail if the command is a variable name
	if ( cvar->variable_string( cmd_name )[0] )
	{
		return;
	}

	// fail if the command already exists
	if ( cmd = cmd_functions; cmd ; cmd = cmd->next )
	{
		if ( !strcmp( cmd_name, cmd->name ) )
		{
			printf("Command::add_command: %s already defined\n", cmd_name );
		}
	}
	cmd = new ( sizeof( Command::Func ));
	cmd->name = cmd_name;
	cmd->function = function;
	cmd->next = cmd_functions;
}

void Command::remove_command( char* cmd_name )
{
	Command::Func* cmd, **back;

	back = &cmd_functions;
	while(1)
	{
		cmd = *back;
		if ( !cmd )
		{
			printf( "Command::remove_command: %s not added\n", cmd_name );
			return;
		}
		if ( !strcmp( cmd_name, cmd->name ) )
		{
			*back = cmd->next;
			delete cmd;
		}
		back = &cmd->next;
	}
}

bool Command::exists( char* cmd_name )
{
	Command::Func* cmd;

	for( cmd = cmd_functions; cmd; cmd = cmd->next )
	{
		if ( !strcmp( cmd_name, cmd->name ) )
			return true;
	}

	return false;
}


char* Command::complete_command( char* partial )
{
	Command::Func* cmd;
	int len;
	Alias *a;

	len = strlen( partial );

	if ( !len )
		return NULL;

	// check for exact match
	for ( cmd = cmd_functions; cmd ; cmd = cmd->next )
		if ( !strncmp( partial, cmd->name, len ) )
			return cmd->name;
	for ( a = cmd_alias; a ; a = a->next )
		if ( !strcmp( partial, a->name )
			return a->name;

	// check for partial match
	for ( cmd = cmd_functions; cmd ; cmd = cmd->next )
		if ( !strncmp( partial, cmd->name, len ) )
			return cmd->name;

	for ( a = cmd_alias; a ; a = a->next )
		if ( !strncmp( partial, a->name, len ) )
			return a->name;

	return NULL;
}

void Command::execute_string( char* text )
{
	Command::Func* cmd;
	Alias* a;

	tokenize_string( text, true );

	if ( !argc() )
		return;

	// check functions
	for ( cmd = cmd_functions; cmd ; cmd = cmd->next )
	{
		if ( !strcasecmp( cmd_argv[0], cmd_name ) )
		{
			cmd->function();
			return;
		}
	}

	// check for alias
	for ( a = cmd_alias; a ; a = a->next )
	{
		if ( !strcasecmp( cmd_argv[0], a->name ) )
		{
			if ( ++alias_count == ALIAS_LOOP_COUNT )
			{
				printf( "ALIAS_LOOP_COUNT\n" );
			}
			insert_text( a->value );
			return;
		}
	}

	// check cvars
}

void Command::execute_text( int exec_when, char* text )
{
	switch( exec_when )
	{
	case EXEC_NOW:
		execute_string( text );
		break;
	case EXEC_INSERT:
		insert_text( text );
		break;
	case EXEC_APPEND:
		add_text(text);
		break;
	default:
		error( ERR_FATAL, "Command::execute_text: bad exec_when" );
	}
}

void Command::execute(void)
{
	int i;
	char *text;
	char line[1024];
	int quotes;

	alias_count = 0;
	while( cursize )
	{
		// find a \n or line break
		text = ( char*) data;
		quotes = 0;

		for ( i = 0; i < cursize; i++ )
		{
			if ( text[i] == '"' )
				quotes++;
			if ( !( qoutes&1) && text[i] == ';' )
				break;
		}

		memcpy( line, text, i );
		line[i] = 0;

		// delete the text from the command buffer and move remaining commands down
		// this is necessary because commands ( exec, alias ) can insert data at the
		// begining of text buffer.

		if ( i == cursize )
			cursize = 0;
		else
		{
			i++;
			cursize -= i;
			memmove( text, text+1, cursize );
		}

		// execute command line
		execute_string( line );
		
		if ( cmd_wait )
		{
			cmd_wait = false;
			break;
		}
	}
}

void Command::add_early_commands( void )
{
}

void Command::add_late_commands( void )
{
}

bool Command::command_cvar(void)
{
	CommandVariable* v;

	//check variables
	v = find_variable( argv[0] );
	if (!v)
		return false;

	// print variable
	if( argc() == 1 )
	{
		printf( "\"%s\" is \"%s\"\n", v->name, v->string );
		return true;
	}

	cvar_set( v->name, argv(1) );
	return true;
}

//===================================================================

						SCRIPT COMMANDS

//===================================================================

void Command::cvar_set_f()
{
	int c;
	int flags;

	c = argc();
	if ( c != 3 && c != 4 )
	{
		printf( "usage: set <variable> <value> [ u / s ]\n" );
		return;
	}

	if ( c == 4 )
	{
		if ( !strcmp( argv(3), "u") )
			flags = CVAR_USERINFO;
		// possible different flags
		else
			printf ( "flag can only be 'u' \n" );

		full_set( argv(1), argv(2), flags );
	}
	else
		cvar_set( argv(1), argv(2) );
}

void Command::exec_f( void )
{
	char *f, *f2;
	int len;

	if ( argc() != 2 )
	{
		printf( "exec <filename>: execute a script file\n" );
		return;
	}

	len = File::load( argv(1), (void **) &f);
	if ( !f )
	{
		printf( "couldn't exec %s\n", argv(1) );
		return;
	}

	printf( "execing %s\n", argv(1) );
	f2 = Memory::malloc( len + 1 );
	memcpy( f2, f, len );
	f2[len] = 0;

	insert_text( f2 );

	Memory::Free( f2 );
	File::free_file( f );
}

/*
========================
Prints the rest of the line to the console
========================
*/
void Command::echo_f( void )
{
	int i;
	for ( i = 1; i < argc(); i++ )
		printf( "%s ", argv(i) );
	printf( "\n" );
}

/*
========================
Creates a new command ( alias )
========================
*/
void Command::alias_f( void )
{
	Alias *a;

	char*  cmd[1024];
	int    i,c;
	char   *s;

	if ( argc() == 1 )
	{
		printf( "Current alias commands:\n" );
		for ( a = cmd_alias; a ; a = a->next )
			printf( "%s : %s\n", a->name, a->value );
		return;
	}

	s = argv(1);	

	if ( strlen(s) >= MAX_ALIAS_NAME )
	{	
		printf( "Alias name is too long\n" );
		return;
	}

	// if the alias already exists, reuse it
	for ( a = cmd_alias; a ; a = a->next )
	{
		if ( !strcmp( s, a->name ) )
		{
			Memory::Free( a->value );
			break;
		}
	}

	if ( !a )
	{
		a = Memory::malloc( Alias );
		a->next = cmd_alias;
		cmd_alias = a;
	}

	strcpy( a->name, s );

	// copy the rest of the command line
	cmd[0] = 0;  // start out with a null string
	c = argc();
	for ( i = 2; i < c; i++ )
	{
		strcat( cmd, argv(i) );
		if ( i != (c - 1) )
			strcat( cmd, " " );
	}
	strcat( cmd, "\n" );

	a->value = copy_string( cmd );
}






